﻿namespace DistrRTgen
{
    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.IO;
    using System.Runtime.CompilerServices;

    public class WUProcess : WorkThread
    {
        private int _NumTimesStarted = 0;
        private Process _Process;
        private WorkUnit _WU;

        private event EventHandler _ProcessExited;

        public WUProcess(WorkUnit WU, EventHandler ProcessExited)
        {
            this._WU = WU;
            this._WU.BeginUse();
            this._WU.WURemoved += new WorkUnit.cuWURemoved(this.WURemoved);
            this._ProcessExited = ProcessExited;
        }

        public long GetNumChainsDone()
        {
            if (File.Exists(this._WU.PartID + ".part"))
            {
                FileInfo fi = new FileInfo(this._WU.PartID + ".part");
                return (fi.Length / 0x10L);
            }
            return 0L;
        }

        public int GetPercentDone()
        {
            return (int) ((((double) this.GetNumChainsDone()) / ((double) this._WU.ChainCount)) * 100.0);
        }

        public int IsDone()
        {
            if (this.GetNumChainsDone() == this._WU.ChainCount)
            {
                return 1;
            }
            if (this._Process.HasExited)
            {
                return -1;
            }
            return 0;
        }

        public void Restart()
        {
            Logger.AddLogLine(string.Concat(new object[] { "Restarting WUProcess for part ", _WU.PartID, "( ", this.NumTimesStarted, " time(s))" }), LoggerLevel.LOG_INFO);
            this.Start();
        }

        public override void Start()
        {
            try
            {
                Logger.AddLogLine(string.Concat(new object[] { "Starting WUProcess ", _WU.PartID, " using ", Environment.CurrentDirectory, "/bin/distrrtgen_", Settings.cmdArchitecture, "_", Settings.cmdVersion, ".exe" }), LoggerLevel.LOG_DEBUG);
                this._Process = new Process();
                this._Process.StartInfo.FileName = "bin/distrrtgen_" + Settings.cmdArchitecture + "_" + Settings.cmdVersion + ".exe";
                this._Process.StartInfo.Arguments = string.Concat(new object[] { 
                    this._WU.PartID, ".part ", this._WU.HashRoutine, " ", this._WU.Charset, " ", this._WU.MinLetters, " ", this._WU.MaxLetters, " ", this._WU.Index, " ", this._WU.ChainLength, " ", this._WU.ChainCount, " ", 
                    this._WU.ChainStart, " ", this._WU.Salt
                 });
                this._Process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                this._Process.StartInfo.UseShellExecute = false;
                this._Process.StartInfo.RedirectStandardError = true;
                this._Process.StartInfo.RedirectStandardOutput = true;
                this._Process.StartInfo.CreateNoWindow = true;
                this._Process.EnableRaisingEvents = true;
                this._Process.StartInfo.WorkingDirectory = Environment.CurrentDirectory;
                this._Process.Exited += this._ProcessExited;
                this._Process.Start();
                if (!this._Process.HasExited)
                {
                    this._Process.PriorityClass = ProcessPriorityClass.Idle;
                }
            }
            catch (Win32Exception ex)
            {
                Logger.AddLogLine(string.Concat(new object[] { "Unable to start WUProcess ", _WU.PartID, ": ", ex.Message }), LoggerLevel.LOG_ALERT);
            }
            this._NumTimesStarted++;
        }

        public override void Stop()
        {
            if (((this._Process != null) && !this._Process.HasExited) && (this._Process.Id != 0))
            {
                Logger.AddLogLine("Stopping WUProcess for part " + _WU.PartID, LoggerLevel.LOG_DEBUG);
                this._Process.Kill();
                this._Process = null;
            }
            this._WU.StopUse();
        }

        private void WURemoved()
        {
            Logger.AddLogLine("WU " + this.PartID + " removed. Stopping process", LoggerLevel.LOG_DEBUG);
            this.Stop();
        }

        public int NumTimesStarted
        {
            get
            {
                return this._NumTimesStarted;
            }
        }

        public uint PartID
        {
            get
            {
                return _WU.PartID;
            }
        }
        public WorkUnit Work
        {
            get
            {
                return _WU;
            }
        }

        public int ProcessID
        {
            get
            {
                if (this._Process != null)
                {
                    return this._Process.Id;
                }
                return 0;
            }
        }

        public StreamReader StdErr
        {
            get
            {
                return this._Process.StandardError;
            }
        }

        public StreamReader StdOut
        {
            get
            {
                return this._Process.StandardOutput;
            }
        }

        public delegate void cuProcessExited();
    }
}

